/*
 * Created on 6 avr. 2005 by Tudor.Ionescu@supelec.fr
 */
package clustering.implementations;
import java.io.*;
import java.util.*;
import clustering.framework.*;
/**
 * @author Tudor.Ionescu@supelec.fr
 * @ Hybrid Compression Based Cluster Tree Constructor
 */
public class HCClusterTreeConstructor implements IHybridClusterTreeConstructor{
    public String ConstructXMLTree(String [] filesList, ICompressor comp)throws Exception{
        // get the length of every file
        File f, comp_f = null;
        long [] fileSizes = new long[filesList.length];
        long [] compFileSizes = new long[filesList.length];
        double [] compFactors = new double[filesList.length];
        double [] idealFactors = new double[filesList.length];
        long [] fileSetSizes = new long[filesList.length];
        for(int i=0;i<filesList.length;i++){
            f = new File(filesList[i]);
            fileSizes[i] = f.length();
            if(i > 0){
                fileSetSizes[i] += fileSetSizes[i-1] + fileSizes[i]; 
            }else{
                fileSetSizes[i] = fileSizes[i];
            }
        }
        
        long [] compFileSetSizes = new long[filesList.length];
        f = new File(filesList[0]);
        comp_f = comp.Compress(f);
        compFactors[0] = (double)comp_f.length() / (double)f.length();
        compFileSizes[0] = comp_f.length();
        
        for(int i=1;i<filesList.length;i++){
            long pointer = 0; 
            FileOutputStream fos = new FileOutputStream("fileset_"+i+".tmp");
            for(int j=0;j<=i;j++){
                FileInputStream fis = new FileInputStream(filesList[j]);
                byte [] file_data = new byte[(int)fileSizes[j]];
                fis.read(file_data);
                fis.close();
                fos.write(file_data);                
            }
            fos.close();
            
            f = new File("fileset_"+i+".tmp");
            comp_f = comp.Compress(f);
            compFileSizes[i] = comp_f.length();
            compFactors[i] = ((double)comp_f.length() - compFileSizes[i-1]) / (double)fileSizes[i];
            idealFactors[i] = IdealCompressionFactor(f);
        }
        
        // compute f_avg - the avarage compression factor
        double sum = 0, isum = 0;
        for(int i=1;i<compFactors.length;i++){
            sum += compFactors[i];
            isum += idealFactors[i];
        }
        double f_avg = sum / (double)(compFactors.length - 1);
        double i_avg = isum / (double)(idealFactors.length - 1);
        
        Taxon [] sortedFiles = new Taxon[filesList.length];       
                
        for(int i=0;i<filesList.length;i++){
           sortedFiles[i] = new Taxon(filesList[i],compFactors[i]);
        }
        
        Arrays.sort(sortedFiles);
        
        /*
        for(int i = filesList.length - 1;i>0;i--){
            if(compFactors[i] - idealFactors[i] < f_avg - i_avg){
                alCandidateFiles.add(filesList[i]);
            }else{
                alCandidateFiles.add(0,filesList[i]);
                // do computation
                //alCandidateFiles.clear();
            }
        }
        */
        
        return null;
    }
    double IdealCompressionFactor(File f) throws Exception{
        FileInputStream fis = new FileInputStream(f);
        byte [] data = new byte[(int)f.length()];
        fis.read(data);
        int [] P = new int[256];
        for(int i=0;i<data.length;i++){
            P[Math.abs((int)data[i])]++;
        }
        double H = 0;
        for(int i=0;i<256;i++){
            if(P[i]!=0){
                H += ((double)P[i]/256)*Math.log((double)P[i]/256);
            }
        }
        return H / f.length();
    }
}
class Taxon implements Comparable{
    public String filename;
    public double score;
    public Taxon(String filename, double score){
        this.filename = filename;
        this.score = score;       
    }
    public int compareTo(Object o){
        Taxon t = (Taxon)o;
        if(score < t.score)return -1;
        if(score > t.score)return 1;
        return 0;        
    }
}
